﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using System.Runtime.InteropServices;
using System.Reflection;
using CoreLib.MySQL.Mapping;

namespace CoreLib.MySQL
{
    public class DbUpdate : DbBaseQuery<DbUpdate>, IDbQuery, IDisposable
    {
        private DbProvider dbProvider;
        public DbUpdate(DbProvider dbProvider)
        {
            this.dbProvider = dbProvider;
            base.TQuery = this;
        }

        public DbUpdate Update(string table)
        {
            base.table = table;
            return this;
        }

        public DbUpdate Set(string column, object value)
        {
            return base.AddParam(column, value);
        }

        public new DbUpdate Where(string column, Comparisson comparer, object value)
        {
            return base.Where(column, comparer, value);
        }

        public new DbUpdate And(string column, Comparisson comparer, object value)
        {
            return base.And(column, comparer, value);
        }

        public new DbUpdate Or(string column, Comparisson comparer, object value)
        {
            return base.Or(column, comparer, value);
        }

        public new DbUpdate Limit(int limit)
        {
            return base.Limit(limit);
        }

        public DbUpdate Update<T>(ref T TObject)
        {
            List<DbFieldAttribute> fields = DbMap.GetMap(typeof(T));
            foreach (var field in fields)
            {
                if (field.isProperty)
                {
                    var property = field.memberInClass as PropertyInfo;
                    Set(field.ColumnName, property.GetValue(TObject, null));
                }
                else
                {
                    var val = field.memberInClass as FieldInfo;
                    Set(field.ColumnName, val.GetValue(TObject));
                }
            }
            return this;
        }

        public unsafe void Execute()
        {
            using (MySqlCommand cmd = new MySqlCommand())
            {
                StringBuilder queryBuilder = new StringBuilder();
                queryBuilder.AppendFormat("Update {0} Set <V> <W>", table);
                if (limit != 0) queryBuilder.AppendFormat(" Limit {0}", limit);
#if UNMANAGED
                string[] values = new string[base.queryClauses.Count];
                for (int i = 0; i < values.Length; i++)
                {
                    string param = base.GetParameter();
                    QuerySegment* segment = (QuerySegment*)base.queryClauses.Dequeue();
                    cmd.Parameters.AddWithValue(values[i], new string(segment->Value));
                    values[i] = string.Format("{0} = {1}", new string(segment->Column), new string(segment->Value));
                    Marshal.FreeHGlobal((IntPtr)segment);
                }
                queryBuilder.Replace("<V>", string.Join(",", values));

                string[] locations = new string[base.whereClauses.Count];
                for (int i = 0; i < locations.Length; i++)
                {
                    string param = base.GetParameter();
                    QuerySegment* segment = (QuerySegment*)base.whereClauses.Dequeue();
                    cmd.Parameters.AddWithValue(param, new string(segment->Value));
                    locations[i] = string.Format("{0} {1} {2} {3}", segment->Connector.ToString(), new string(segment->Column), TranslateOperator(segment->Comparisson), param);
                    Marshal.FreeHGlobal((IntPtr)segment);
                }
                queryBuilder.Replace("<W>", string.Join(" ", locations));
#else
                string[] values = new string[base.queryClauses.Count];
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = base.GetParameter();
                    QuerySegment segment = base.queryClauses.Dequeue();
                    cmd.Parameters.AddWithValue(values[i], segment.Value);
                    values[i] = string.Format("{0} = {1}", segment.Column, values[i]);
                }
                queryBuilder.Replace("<V>", string.Join(",", values));

                string[] locations = new string[base.whereClauses.Count];
                for (int i = 0; i < locations.Length; i++)
                {
                    string param = base.GetParameter();
                    QuerySegment segment = (QuerySegment)base.whereClauses.Dequeue();
                    cmd.Parameters.AddWithValue(param, segment.Value);
                    locations[i] = string.Format("{0} {1} {2} {3}", segment.Connector.ToString(), segment.Column, TranslateOperator(segment.Comparisson), param);
                }
                queryBuilder.Replace("<W>", string.Join(" ", locations));

#endif
                using (cmd.Connection = dbProvider.CreateDbConnection())
                {
                    cmd.CommandText = queryBuilder.ToString();
                    cmd.ExecuteNonQuery();
                }
            }
        }

        public void Dispose()
        {
            //TODO
        }
    }
}
